package initialize

import (
	"context"
	"errors"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"go.uber.org/zap"
	"xincan.com.cn/tarot-go-framework/global"
	"xincan.com.cn/tarot-go-framework/router"
)

// Start
// Title 系统启动
// Author  alittlexincan@163.com 2024/07/22 11:36
// Update  alittlexincan@163.com 2024/07/22 11:36
func Start() {
	// 创建一个可取消的context
	ctx, stop := context.WithCancel(context.Background())

	// 设置信号处理
	setupSignalHandler(stop)

	// 启动HTTP服务器
	go startServer(ctx)

	// 阻塞主goroutine，直到接收到停止信号
	<-ctx.Done()
	global.Logger.Info("服务关闭成功")

	// 执行清理动作, 关闭数据库连接, 关闭文件句柄等, 避免资源泄露等等
	// 关闭数据库连接
	closeMysql()
}

// setupSignalHandler
// Title 设置信号处理
// Author  alittlexincan@163.com 2024/07/22 11:36
// Update  alittlexincan@163.com 2024/07/22 11:36
func setupSignalHandler(stop context.CancelFunc) {
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		sig := <-sigs
		global.Logger.Info("服务接收信号处理中...", zap.Any("signal", sig))
		stop()
	}()
}

// startServer
// Title 启动HTTP服务
// Author  alittlexincan@163.com 2024/07/22 11:36
// Update  alittlexincan@163.com 2024/07/22 11:36
func startServer(ctx context.Context) {
	port := global.AppConfig.Service.Port
	srv := &http.Server{Addr: ":" + port, Handler: router.Router()}
	// 初始化日志
	global.Logger.Info("API-V3-文档地址", zap.String("url", "http://localhost:"+port+"/v3/swagger/index.html"))
	global.Logger.Info("API-V2-文档地址", zap.String("url", "http://localhost:"+port+"/v2/swagger/index.html"))
	global.Logger.Info("服务启动成功", zap.String("port", port))
	go func() {
		if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			global.Logger.Error("服务启动失败", zap.Any("err", err))
			panic("服务启动失败")
		}
	}()
	<-ctx.Done()
	// 等待5秒，优雅地关闭HTTP服务器
	shutdownServer(srv)
}

// shutdownServer
// Title 优雅地关闭HTTP服务
// Author  alittlexincan@163.com 2024/07/22 11:36
// Update  alittlexincan@163.com 2024/07/22 11:36
func shutdownServer(srv *http.Server) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	global.Logger.Info("等待5秒, 服务关闭中...")
	if err := srv.Shutdown(ctx); err != nil {
		global.Logger.Error("服务关闭失败", zap.Any("err", err))
		panic("服务关闭失败")
	}
	global.Logger.Info("服务关闭成功")
}

// closeMysql
// Title 优雅地关闭数据库连接
// Author  alittlexincan@163.com 2024/07/22 11:36
// Update  alittlexincan@163.com 2024/07/22 11:36
func closeMysql() {
	if db, err := global.DBClient.DB(); err != nil {
		global.Logger.Error("关闭数据库连接失败", zap.Any("err", err))
	} else {
		if err = db.Close(); err != nil {
			global.Logger.Error("关闭数据库连接失败", zap.Any("err", err))
		}
		global.Logger.Info("关闭数据库连接成功")
	}

}
